package xyz.scootaloo.kami.cloud.model.po

import io.vertx.core.json.JsonObject
import xyz.scootaloo.kami.cloud.lang.JsonSerializable
import xyz.scootaloo.kami.cloud.lang.JsonSerializer
import xyz.scootaloo.kami.cloud.lang.deserializer
import xyz.scootaloo.kami.cloud.model.core.SC
import xyz.scootaloo.kami.cloud.model.core.StatusCode
import kotlin.reflect.KClass

/**
 * @author flutterdash@qq.com
 * @since 2022/4/12 17:23
 */
typealias SR<T> = ServiceResult<T>

data class ServiceResult<T : Any>(
    val code: StatusCode = StatusCode.SUCCEED,
    var result: T? = null
) : JsonSerializable {

    fun succeeded(): Boolean = code.succeeded

    fun toUnit(): ServiceResult<Unit> {
        return ServiceResult(code)
    }

    companion object {
        const val resultKey = "result"

        fun <T : Any> error(code: SC = SC.FAILURE): ServiceResult<T> {
            return of(code)
        }

        fun unit(code: SC): ServiceResult<Unit> {
            return of(code)
        }

        fun <T : Any> of(code: SC): ServiceResult<T> {
            return ServiceResult(code)
        }

        inline fun <reified T : Any> deserialize(json: JsonObject): ServiceResult<T> {
            val code: StatusCode = deserializer(json.getJsonObject("code"))
            if (json.getValue(resultKey) == null) {
                return SR(code, null)
            }

            return when (T::class) {
                Boolean::class -> SR(code, json.getBoolean(resultKey) as T?)
                Byte::class -> SR(code, json.getInteger(resultKey).toByte() as T?)
                Short::class -> SR(code, json.getInteger(resultKey).toShort() as T?)
                Int::class -> SR(code, json.getInteger(resultKey) as T?)
                Float::class -> SR(code, json.getFloat(resultKey) as T?)
                Double::class -> SR(code, json.getDouble(resultKey) as T?)
                Long::class -> SR(code, json.getLong(resultKey) as T?)
                String::class -> SR(code, json.getString(resultKey) as T?)
                Unit::class -> SR(code, Unit as T?)
                JsonObject::class -> SR(code, json.getJsonObject(resultKey) as T?)
                JsonSerializable::class -> SR(code, deserializer(json.getJsonObject(resultKey)))
                else -> {
                    throw IllegalStateException("类型'${T::class.simpleName}'不是可反序列化的类型")
                }
            }
        }
    }
}

object ServiceResultSerializer : JsonSerializer<ServiceResult<*>> {
    override fun accept(): KClass<ServiceResult<*>> {
        return ServiceResult::class
    }

    override fun deserialize(json: JsonObject): ServiceResult<*> {
        /**
         * 上下文中缺少信息, 无法推导出泛型类型;
         * 请使用 [ServiceResult.deserialize]
         */
        throw IllegalAccessException("类型'ServiceResult'不可直接反序列化")
    }
}